#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
sys.path.append('../')
import regex
import copy

import click
import requests

from utils import tp_logging
from utils import tp_config

from . import text_extractor

logger = tp_logging.get_logger('lyrics_parser')


class Session(object):
    def __init__(self):
        self.session = requests.Session()

    def get(self, url, **kwargs):
        response = self.session.get(
            url=url,
            headers={
                'user-agent': (
                    'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) '
                    'Gecko/20100101 Firefox/60.0')
            },
            verify=False,
            **kwargs
        )

        return response


class LyricsParser(object):
    def __init__(self):
        self.artist = None
        self.song = None
        self.session = Session()

    @staticmethod
    def fix_html_common_semantic_issues(html):
        """Fixes common HTML issues
        :param html: HTML text to be fixed
        :return: HTML text passed through fixing
        """

        # 1 - <br /> tags inside <p>
        if regex.search('<p>.{1,50}<br', html) is not None:
            html = regex.sub('(<br.{0,3}>)', '</p><p>', html)

        # 2 - \r removal
        html = html.replace('\r', '')

        # 3 - Remove extra line breaks
        html = regex.sub('\n{2,}', '\n', html)

        return html

    def fetch_from_web(self, searx_results_index=0):
        """Gets and visits Searx results for specific keywords
        :param searx_results_index: Index in search results
        :return: Summary of visited result
        """
        # Search anonymously with Searx, must have "lyrics",
        # must not have "youtube" etc

        must_not_have = [
            'youtube',
            'amazon',
            'wiki',
            'error',
            'music',
            'docs',
            'album'
        ]

        must_not_have = ' -'.join(must_not_have)

        payload_searx = {
            'q': '"{}" "{}" "lyrics" -{}'.format(
                self.artist, self.song, must_not_have),
            'categories': 'general',
            'format': 'json',
            'language': 'en-US'
        }

        searx_reponse = self.session.get(
            url=tp_config.get_config()['searx_instance_url'],
            params=payload_searx)

        searx_json = searx_reponse.json()

        top_lyrics_url = searx_json['results'][searx_results_index]['url']

        decoded_response_content = self.session.get(
            url=top_lyrics_url).content.decode('utf-8')
        html = self.fix_html_common_semantic_issues(
            html=decoded_response_content)

        return text_extractor.extract_summary(html)

    def clean_lyrics_keywords(self, lyrics_summary):
        """Removes known common elements found around lyrics
        :parameter: lyrics_summary: Summary/text with lyrics keywords
        :return: List of lines with keywords cleaned
        """

        lyrics_lines = [line.strip() for line in lyrics_summary.split('\n')]

        # Remove lines containing "lyrics", "chorus" etc, white spaces, empty
        # items
        copy_lines = copy.copy(lyrics_lines)

        for line_index, line in enumerate(copy_lines):
            # Remove song title from lyrics beginning
            if line_index == 0 and self.song in line:
                lyrics_lines.remove(line)

            # Remove keywords
            if regex.search(r'video|lyrics|chorus|writer|:|author|"|html|'
                            r'upload|'
                            r'<|>|'
                            r'\s{2,}|'
                            r'^(:?[$=\s]+)|'
                            r'^$',
                            line,
                            regex.IGNORECASE
                            ) is not None:
                lyrics_lines.remove(line)

        return lyrics_lines

    def get_lyrics(self, artist, song):
        """Starts searching and then parsing, retrying when needed
        :param artist: The song's artist name
        :param song: The song's title
        :return: List containing lyrics lines
        """

        logger.info('%s - %s', artist, song)

        self.artist = artist
        self.song = song

        clean_lyrics = None

        # Try 3 different sources/Searx results
        for retry in range(0, 3):
            logger.debug('Trying Searx result %d', retry + 1)
            summary = self.fetch_from_web(searx_results_index=retry)
            clean_lyrics = self.clean_lyrics_keywords(lyrics_summary=summary)

            # More than 10 lines
            if len(clean_lyrics) > 10:
                break

        return clean_lyrics

@click.command()
@click.option('--song', help='Song title', required=True)
@click.option('--artist', help='Artist name', required=True)
def get_lyrics_cli(song, artist):
    lyrics_parser = LyricsParser()
    lyrics = lyrics_parser.get_lyrics(song=song, artist=artist)
    print(lyrics)

if __name__ == '__main__':
    get_lyrics_cli()

